package pt.ua.helpdesk.server;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import persistence.Administrator;
import persistence.Assignment;
import persistence.AssignmentPK;
import persistence.Assistant;
import persistence.Command;
import persistence.Comment;
import persistence.Person;
import persistence.Ticket;
import persistence.Utilizador;
import pt.ua.helpdesk.client.ServiceTickets;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

/**
 * Servlet responsible for actions related to tickets
 * 
 * @author Amigos do Noddy
 *
 */
public class ServiceTicketsImpl extends RemoteServiceServlet implements ServiceTickets 
{
	private static final long serialVersionUID = -7894617820080343852L;
	
	/**
	 * Add a ticket
	 * 
	 * @param title Title of the ticket
	 * @param question Question placed by the user
	 * @param status Status of the ticket (1 - Pending; 2 - Solving; 3 - Solved)
	 * @param active Indicates whether the ticket is active or not (1 - Active; 0 - Inactive)
	 * @param idPerson ID of the author of the ticket 
	 * @return True in case of ticket successfully added, False otherwise
	 */
	public Boolean addTicket(String title, String question, Integer status, Integer active, Integer idPerson)
	{
		Ticket ticket = new Ticket();
		boolean ret;
		
		Date date = new Date();
		ticket.setTitle(title);
		ticket.setTicket(question);
		ticket.setStatus(status.shortValue());
		ticket.setActive(active.shortValue());
		ticket.setDate(date);
		
		ticket.setRefidpersonUtilizador((Utilizador) Command.find(Utilizador.class, idPerson));
		
		ret = Command.set(ticket);
		
		return new Boolean(ret);
	}
	
	/**
	 * Removes a ticket
	 * 
	 * @param idTicket ID of the ticket to be removed
	 * @return True in case of successful removal, False otherwise
	 */
	public Boolean removeTicket(Integer idTicket)
	{
		/*
		 * TODO
		 * Tratar do problema de saber se � um user assistente ou adm
		 * Onde tratar desse problema? Do lado do cliente ou do server?
		 * */
		boolean ret;
		Ticket ticket = (Ticket)Command.find(Ticket.class, idTicket);
		
		ticket.setActive((short)0);
		
		ret = Command.update(ticket);
		
		return new Boolean(ret);
		
		
		}

	/**
	 * Retrieves a list of pending tickets of a given user
	 * 
	 * @return ArrayList of the pending tickets
	 */
	public ArrayList getPendingTickets() 
	{
		ArrayList<Object> Tickets  = new ArrayList<Object>();
		ArrayList<Object> idTickets = new ArrayList<Object>();
		ArrayList<Object> title = new ArrayList<Object>();
		ArrayList<Object> dates = new ArrayList<Object>();
		
		ArrayList<Integer> par = new ArrayList<Integer>();
	
		par.add(new Integer(1));//ACTIVE
		par.add(new Integer(1));//PENDING
		List<Ticket> l = (List<Ticket>)Command.select("select t from Ticket t where (t.active = ?1) and (t.status = ?2)", par);
		for(int i = 0; i < l.size(); i++)
		{
			idTickets.add(new Integer(l.get(i).getIdticket()));
			title.add(new String(l.get(i).getTitle()));
			dates.add(new String(l.get(i).getDate().toLocaleString()));
		}
			
		Tickets.add(idTickets);
		Tickets.add(title);
		Tickets.add(dates);
		
		return Tickets;
	}

	/**
	 * Retrieves complete data on a ticket, including info and comments
	 *  
	 * @param ticketId ID of the ticket to be searched
	 * @return An ArrayList containing an ArrayList with the ticket info, and another with the ticket's comments
	 */
	public ArrayList<Object> loadFullTicketData(Integer ticketId) {
		ArrayList<Object> ret = new ArrayList<Object>() ;

		Ticket t = (Ticket)Command.find(Ticket.class, ticketId);
		
		ret.add(loadTicketInfo(t));
		ret.add(loadTicketComments(t.getCommentCollection()));
		
		return ret ;
	}
	
	/**
	 * Retrieves data necessary to assign a ticket to an assistant
	 *  
	 * @param ticketId ID of the ticket to be searched
	 * @return An ArrayList containing the ticket info and a list of active assistants 
	 */
	public ArrayList loadDataForAssignment(Integer ticketId) {
		ArrayList<Object> ret = new ArrayList<Object>() ;
		Ticket t = (Ticket)Command.find(Ticket.class, ticketId.intValue());
		
		ArrayList<Object> param = new ArrayList<Object>() ;
		param.add("Assistente");
		param.add((short)1); // value for active person
		String sql = "select p from Person p where (p.PersonType = ?1) AND (p.active = ?2)" ;
		List<Person> l = (List<Person>) Command.select(sql, param);
		//loadAssistantsNames(l);
		ret.add(loadTicketInfo(t)) ;
		ret.add(loadAssistantsNames(l));
		
		return ret ;
	}

	/**
	 * Retrieves a list of tickets on charge of a specific user 
	 * 
	 * @param IDUser ID of the user
	 * @return ArrayList containing all active tickets of the assistant
	 */
	public ArrayList getUserTickets(Integer idUser) {
		
		ArrayList<Object> Tickets  = new ArrayList<Object>();
		
		
		ArrayList<Object> idTickets = new ArrayList<Object>();
		ArrayList<Object> title = new ArrayList<Object>();
		ArrayList<Object> status = new ArrayList<Object>();
		ArrayList<Object> par = new ArrayList<Object>();
		
		
		
		par.add(Command.find(Utilizador.class, idUser));
		par.add(new Integer(1));
		List<Ticket> l = (List<Ticket>)Command.select("select t from Ticket t where (t.refidpersonUtilizador = ?1) and (t.active = ?2)", par);
		for(int i = 0; i < l.size(); i++)
		{
			idTickets.add(new Integer(l.get(i).getIdticket()));
			title.add(new String(l.get(i).getTitle()));
			status.add(new String(new Integer((int)l.get(i).getStatus()).toString()));
		}
			
		Tickets.add(idTickets);
		Tickets.add(title);
		Tickets.add(status);
		
		return Tickets;
		

	}

	/**
	 * Retrieves a list of tickets on charge of a specific assistant 
	 * 
	 * @param IDAssistant ID of the assistant
	 * @return ArrayList containing all active tickets of the assistant
	 */
	public ArrayList getAssisTickets(Integer idAssis) {
		
		String sql = new String();
		ArrayList<Object> Tickets  = new ArrayList<Object>();
		int i;
		ArrayList<Object> idTickets = new ArrayList<Object>();
		ArrayList<Object> title = new ArrayList<Object>();
		ArrayList<Object> status = new ArrayList<Object>();
		ArrayList<Object> par1 = new ArrayList<Object>();
		ArrayList<Object> par2 = new ArrayList<Object>();
		
		Person p = (Person)Command.find(Person.class, idAssis);
		par1.add(p);
		
		par1.add(new Integer(1)); //Ticket active
	
		
		sql = "select t from Ticket t, Comment c where ((t = c.refidticket) and (c.refidpersonAuthor = ?1) and (t.active = ?2))";
		List<Ticket> l = (List<Ticket>)Command.select(sql, par1);
		
		for(i = 0; i < l.size(); i++)
		{
			/* Este if serve para resolver o problema do JQL não suportar
			 * a clausula distinct*/
			if(idTickets.contains(l.get(i).getIdticket()) == false)
			{
				idTickets.add(new Integer(l.get(i).getIdticket()));
				title.add(new String(l.get(i).getTitle()));
				status.add(new String(new Integer((int)l.get(i).getStatus()).toString()));
			}
		}
		
		Assistant a = (Assistant)Command.find(Assistant.class, idAssis);
		par2.add(a);
		
		par2.add(new Integer(1)); //Ticket active
		
		sql = "select t from Ticket t, Assignment a where ((a.assistant = ?1) and (t.active = ?2) and (t = a.ticket))";
		/* Duas listas pk o JQL não suporta UNION
		 * */
		List<Ticket> l2 = (List<Ticket>)Command.select(sql, par2);
		
		for(i = 0; i < l2.size(); i++)
		{
			idTickets.add(new Integer(l2.get(i).getIdticket()));
			title.add(new String(l2.get(i).getTitle()));
			status.add(new String(new Integer((int)l2.get(i).getStatus()).toString()));
		}
		Tickets.add(idTickets);
		Tickets.add(title);
		Tickets.add(status);
		
		return Tickets;
		

	}
	
	
	/**
	 * Adds a comment to a ticket
	 * 
	 * @param authorId ID of the author of the ticket
	 * @param ticketId ID of the ticket
	 * @param text Text of the comment
	 * @return True in case of successful removal, False otherwise
	 */
	public Boolean addComment(Integer authorId, Integer ticketId, String text) {
		Comment comm = new Comment() ;
		
		Person p = (Person)Command.find(Person.class, authorId) ;
		Ticket t = (Ticket)Command.find(Ticket.class, ticketId) ;
	
		comm.setDate(new Date());
		comm.setComment(text);
		comm.setRefidpersonAuthor(p);
		comm.setRefidticket(t);
		
		// if ticket status is pending, alter it to solving
		if ( t.getStatus() == 1 )
			t.setStatus((short)2);
		
		t.getCommentCollection().add(comm) ;
		
		return Command.update(t) ; 
	}
	
	public Boolean assignTicket(Integer assistId, Integer adminId, Integer ticketId) {
		Assignment assignment = new Assignment();
		Ticket ticket = (Ticket)Command.find(Ticket.class, ticketId.intValue());
		Administrator admin = (Administrator)Command.find(Administrator.class, adminId.intValue());
		Assistant assist = (Assistant)Command.find(Assistant.class, assistId);
		
		// update ticket status to solving 
		ticket.setStatus((short)2) ;
		Command.update(ticket) ;
		
		assignment.setAdministrator(admin) ;
		assignment.setAssistant(assist) ;
		assignment.setTicket(ticket);
		
		AssignmentPK pk = new AssignmentPK();
		pk.setRefidpersonAdm(adminId.intValue());
		pk.setRefidpersonAss(assistId.intValue()) ;
		pk.setRefidticket(ticketId.intValue());
		
		assignment.setAssignmentPK(pk) ;
		
		return Command.set(assignment);
	}
	
	/**
	 * Retrieves all comments of a ticket
	 * 
	 * @param ticketId ID of the selected ticket
	 * @return ArrayList containing all comments
	 */
	private ArrayList<Object> loadTicketComments(Collection<Comment> comms) {
		ArrayList<Object> ticketComs = new ArrayList<Object>() ;
		ArrayList<Object> names = new ArrayList<Object>();
		ArrayList<Object> dates = new ArrayList<Object>();
		ArrayList<Object> comments = new ArrayList<Object>();
		
		int i ;
		Object[] comms_ar = comms.toArray() ;
		for (i = 0; i < comms.size(); i++)
		{
			Comment c = (Comment) comms_ar[i] ;
			names.add(new String(c.getRefidpersonAuthor().getName()));
			dates.add(new String(c.getDate().toString()));
			comments.add(new String(c.getComment()));
		}
		
		ticketComs.add(names);
		ticketComs.add(dates);
		ticketComs.add(comments);
			
		return ticketComs ;
	}

	/**
	 * Retrieves full info of a ticket
	 * 
	 * @param ticketId ID of the selected ticket
	 * @return ArrayList containing full info of the ticket
	 */
	private ArrayList<String> loadTicketInfo(Ticket tckt) {
		ArrayList<String> ticket = new ArrayList<String>();
		String[] stat = {"Pendente", "A Resolver", "Resolvido"} ;
		
		ticket.add(new String(tckt.getTicket()));
		ticket.add(new String(tckt.getTitle()));
		ticket.add(new String(stat[tckt.getStatus()-1]));
		ticket.add(new String(tckt.getRefidpersonUtilizador().getName()));
		ticket.add(new String(tckt.getDate().toString()));
		
		return ticket ;	
	}
	
	/**
	 * Retrieves the names and ids of active assistants
	 * 
	 * @param ticketId ID of the selected ticket
	 * @return ArrayList containing full info of the ticket
	 */
	private ArrayList loadAssistantsNames(List<Person> assists)
	{
		ArrayList list = new ArrayList() ;
		
		for (int i = 0; i < assists.size(); i++)
		{
			Person data = (Person) assists.get(i);
			ArrayList<String> assist = new ArrayList<String>() ;
			
			assist.add((String)data.getName()) ;
			assist.add(data.getIdperson().toString()) ;
			
			list.add(assist) ;
		}
		
		return list ;
	}

	/**
	 * 
	 * @param ticket
	 * @return
	 */
	@Override
	public Boolean setTicketAsSolved(Integer ticket) {
		Ticket t = (Ticket)Command.find(Ticket.class, ticket.intValue());
		
		t.setStatus((short)3) ;
		return new Boolean(Command.update(t)) ;
	}
}
